// Mock类用于替代实际的WebAssembly加载
import fs from "fs";
import path from "path";

class MockParser {
  private fileExtension: string | undefined;
  
  setLanguage(language: any): MockParser {
    return this;
  }
  
  // 设置文件扩展名
  setFileExtension(extension: string): MockParser {
    this.fileExtension = extension;
    return this;
  }
  
  parse(sourceCode: string): MockTree {
    // 返回一个模拟的树结构，并传递文件扩展名
    return new MockTree(sourceCode, this.fileExtension);
  }
}

class MockLanguage {
  static async load(wasmPath: string): Promise<MockLanguage> {
    return new MockLanguage();
  }
}

class MockNode {
  type: string;
  text: string;
  startPosition: { row: number; column: number };
  endPosition: { row: number; column: number };
  children: MockNode[];

  constructor(type: string, text: string, startRow: number, startCol: number, endRow: number, endCol: number) {
    this.type = type;
    this.text = text;
    this.startPosition = { row: startRow, column: startCol };
    this.endPosition = { row: endRow, column: endCol };
    this.children = [];
  }
}

class MockTree {
  rootNode: MockNode;

  constructor(sourceCode: string, fileExtension?: string) {
    // 创建一个模拟的根节点
    this.rootNode = new MockNode("program", sourceCode, 0, 0, sourceCode.split('\n').length - 1, sourceCode.length);
    
    const lines = sourceCode.split('\n');
    
    // 根据文件扩展名选择不同的函数检测逻辑
    if (fileExtension === 'java') {
      // 更精确的Java方法声明正则表达式
      // 匹配格式: [修饰符] [返回类型] [方法名]([参数])
      // 排除了new关键字开头的构造函数调用
      const javaMethodRegex = /^\s*(?!new\s)(public|private|protected|static|final|synchronized|native|abstract|strictfp)?\s+(?:<[\w,\s<>]+>\s+)?[\w<>,.]+\s+([\w<>]+)\s*\(/gm;
      
      // 重新组合源代码为字符串，以便进行多行匹配
      const sourceText = sourceCode;
      let match;
      
      // 为每个方法创建单独的节点
      while ((match = javaMethodRegex.exec(sourceText)) !== null) {
        // 计算匹配的行号
        const linesBeforeMatch = sourceText.substring(0, match.index).split('\n');
        const lineNumber = linesBeforeMatch.length - 1;
        
        // 获取完整的方法声明行
        const lineContent = lines[lineNumber];
        const lineStartPos = sourceText.substring(0, match.index).lastIndexOf('\n') + 1;
        const matchLength = match[0].length;
        
        // 创建方法节点
        const methodName = match[2];
        const methodDeclaration = match[0];
        
        // 尝试提取完整的方法体
        // 在真实的Tree-sitter实现中，这会自动处理，但在我们的Mock实现中，我们需要手动模拟
        let completeMethod = methodDeclaration;
        
        // 计算匹配的行号范围
        let openBraceCount = 0;
        let closeBraceCount = 0;
        let bodyStartLine = lineNumber;
        let bodyEndLine = lineNumber;
        
        // 简单地从当前行开始，查找方法体的结束位置
        // 这是一个简化的实现，真实的Tree-sitter会更准确地处理嵌套的括号
        for (let j = lineNumber; j < lines.length; j++) {
          const line = lines[j];
          // 计算该行的花括号数量
          const opens = (line.match(/{/g) || []).length;
          const closes = (line.match(/}/g) || []).length;
          
          openBraceCount += opens;
          closeBraceCount += closes;
          
          // 如果方法体的括号已经平衡，就找到了方法的结束位置
          if (openBraceCount > 0 && openBraceCount === closeBraceCount) {
            bodyEndLine = j;
            break;
          }
        }
        
        // 提取完整的方法体文本
        for (let j = lineNumber; j <= bodyEndLine; j++) {
          if (j > lineNumber) {
            completeMethod += '\n' + lines[j];
          }
        }
        
        // 创建包含完整方法体的节点
        const funcNode = new MockNode(
          "function_declaration",
          completeMethod, // 现在包含了真实的方法体
          lineNumber, 
          match.index - lineStartPos, 
          bodyEndLine, 
          lines[bodyEndLine].length
        );
        this.rootNode.children.push(funcNode);
      }
    } else {
      // JavaScript函数声明的正则表达式
      const functionRegex = /function\s+([a-zA-Z_$][0-9a-zA-Z_$]*)\s*\(/g;
      
      for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        functionRegex.lastIndex = 0;
        let match;
        while ((match = functionRegex.exec(line)) !== null) {
          const funcName = match[1];
          const funcNode = new MockNode("function_declaration", match[0] + " {...}", i, match.index, i, line.length);
          this.rootNode.children.push(funcNode);
        }
      }
    }
  }
}

class MockQuery {
  captures(rootNode: MockNode): Array<{ node: MockNode, name: string }> {
    const captures: Array<{ node: MockNode, name: string }> = [];
    
    // 模拟查询功能
    rootNode.children.forEach(child => {
      if (child.type === "function_declaration") {
        captures.push({ node: child, name: "function.name" });
      }
    });
    
    return captures;
  }
}

/**
 * 异步加载指定扩展名对应的树解析器语言模块，并设置解析器的语言。
 * @param ext - 文件扩展名，用于确定要加载的解析器语言模块。
 * @returns 返回设置了指定语言的解析器实例。
 * @throws 当传入的扩展名不支持时，抛出错误。
 */
async function loadParser(ext: string) {
  // Mock实现，不实际加载WebAssembly
  const parser = new MockParser();
  const language = new MockLanguage();
  return { parser, language };
}

/**
 * 检查文件是否需要被忽略。
 * @param filePath - 要检查的文件的完整路径。
 * @returns 如果文件需要被忽略则返回 true，否则返回 false。
 */
function checkIgnoreFile(filePath: string): boolean {
  try {
    // 读取忽略文件列表
    const ignoreFileContent = fs.readFileSync(".ignorefiles", "utf8");
    // 将忽略文件列表按行分割成数组
    const ignoreFileArray = ignoreFileContent.split("\n");
    // 检查文件名是否在忽略列表中
    if (ignoreFileArray.includes(filePath)) {
      return true;
    }
  } catch (error) {
    // 如果.ignorefiles文件不存在，则不忽略任何文件
    console.log(".ignorefiles文件不存在，不忽略任何文件");
  }
  return false;
}

/**
 * 用于将指定目录下的代码文件拆分成代码块的类。
 */
class CodeSnapped {
  /**
   * 获取函数的名称
   * @param tree
   * @returns
   */
  async getFunctionNames(tree: MockTree, language: MockLanguage, fileExtension?: string) {
    const rootNode = tree.rootNode;
    const functionNames: string[] = [];

    // 使用 MockQuery 替代实际的 Query
    const parsedQuery = new MockQuery();
    const captures = parsedQuery.captures(rootNode);
    captures.forEach((capture) => {
      // 根据文件类型使用不同的正则表达式提取函数名
      if (fileExtension === 'java') {
        // 匹配Java方法名：[修饰符] [返回类型] [方法名]([参数])
        const javaMethodMatch = capture.node.text.match(/\s*(?:public|private|protected|static|final|synchronized|native|abstract|strictfp)?\s+(?:<[\w,\s<>]+>\s+)?([\w<>,]+\s+)+([\w<>]+)\s*\(/);
        if (javaMethodMatch && javaMethodMatch[3]) {
          functionNames.push(javaMethodMatch[3]);
        }
      } else {
        // 从JavaScript函数声明文本中提取函数名
        const funcMatch = capture.node.text.match(/function\s+([a-zA-Z_$][0-9a-zA-Z_$]*)/);
        if (funcMatch && funcMatch[1]) {
          functionNames.push(funcMatch[1]);
        }
      }
    });

    return functionNames;
  }
  /**
   * 异步遍历指定目录下的所有文件，并将每个文件解析成代码块。
   * @param dirPath - 要遍历的目录路径。
   * @returns 返回包含所有代码块信息的数组。
   */
  async chunkCode(dirPath: string) {
    const chunks: any[] = [];

    /**
     * 递归遍历指定路径的函数。
     * @param currentPath - 当前要处理的路径，可以是文件或目录。
     */
    const traverseDirectory = async (currentPath: string) => {
      // 获取当前路径的文件状态
      const stats = fs.statSync(currentPath);
      if (stats.isDirectory()) {
        // 如果是目录，获取目录下的所有文件和子目录
        const files = fs.readdirSync(currentPath);
        for (const file of files) {
          // 递归调用遍历函数处理子目录和文件
          await traverseDirectory(path.join(currentPath, file));
        }
      } else if (stats.isFile()) {
        // 如果是文件，检查是否需要忽略
        if (checkIgnoreFile(currentPath)) {
          return;
        }
        // 获取文件扩展名
        const fileExtension = path.extname(currentPath).slice(1).toLowerCase();
        if (!fileExtension) {
          throw new Error("Unable to determine file extension");
        }
        // 加载对应的解析器
        const { parser, language } = await loadParser(fileExtension);
        // 读取文件内容
        const sourceCode = fs.readFileSync(currentPath, "utf8");
        // 解析文件内容
        let tree = parser.setFileExtension(fileExtension).parse(sourceCode);
        try {
          if (!tree) {
            console.error(`Failed to parse ${currentPath}`);
            return;
          }
        } catch (error) {
          console.error(`Error parsing ${currentPath}:`, error);
          return;
        }
        // 不再需要getFunctionNames方法，因为我们直接从child.text中提取方法名
        // let funcNames = this.getFunctionNames(tree, language, fileExtension);
        // 获取解析树的根节点
        const rootNode = tree.rootNode;
        // 将代码块信息添加到结果数组中
        for (const child of rootNode.children) {
          if (child?.type === "function_declaration") {
            let funcName = "";
            // 直接从child.text中提取方法名
            if (fileExtension === 'java') {
              // 使用更简单的正则表达式匹配Java方法名
              // 匹配格式: [任意文本] [方法名] ( [参数...] )
              const javaMethodMatch = child.text.match(/\s*(?:public|private|protected|static|final|synchronized|native|abstract|strictfp)?\s+(?:<[\w,\s<>]+>\s+)?[\w<>,.]+\s+([\w<>]+)\s*\(/);
              if (javaMethodMatch && javaMethodMatch[1]) {
                funcName = javaMethodMatch[1];
              }
            } else {
              // 匹配JavaScript函数名
              const funcMatch = child.text.match(/function\s+([a-zA-Z_$][0-9a-zA-Z_$]*)/);
              if (funcMatch && funcMatch[1]) {
                funcName = funcMatch[1];
              }
            }
            chunks.push({
              filePath: currentPath,
              startPosition: child.startPosition,
              endPosition: child.endPosition,
              code: child.text,
              signature: funcName,
            });
          }
        }
      }
    };
    // 开始遍历指定目录
    await traverseDirectory(dirPath);
    return chunks;
  }
}

// 导出 CodeSnapped 类和checkIgnoreFile函数
export default CodeSnapped;
export { checkIgnoreFile };